package com.taotao.common.utils;

import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * redis连接池公共方法类
 * @author tedbai 2018-06-22
 *
 */
public class RedisUtils {

	private static JedisPool pool = null;
	
	private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;

	/**
	 * 得到redis连接池中的连接实例
	 * @return
	 * @throws NullPointerException
	 */
	public static Jedis getJedis() throws NullPointerException{
		if (pool == null){
			throw new NullPointerException("获取redis连接实例时发生异常，连接池未初始化成功！");
		}
		return pool.getResource();
	}
	
	public static void init(String addr){
		init(null, addr);
	}
	
	public static void init(JedisPoolConfig jedisPoolConfig, String addr){
		if (jedisPoolConfig == null){
			pool = new JedisPool(new JedisPoolConfig(), addr);
		} else {
			pool = new JedisPool(jedisPoolConfig, addr);
		}
	}
	
	public static void init(String addr, int port){
		GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
		poolConfig.setMaxTotal(100); // default 8
		poolConfig.setMaxIdle(100); // default 8
		poolConfig.setMinIdle(100); // default 8
		pool = new JedisPool(poolConfig, addr, port, 30000); // 30秒read timeout
	}
	
	public static void init(String addr, int port, String password){
		GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
		poolConfig.setMaxTotal(100); // default 8
		poolConfig.setMaxIdle(100); // default 8
		poolConfig.setMinIdle(100); // default 8
		if (password == null || password.trim().length() == 0) {
			pool = new JedisPool(poolConfig, addr, port, 30000); // 30秒read timeout
		} else {
			pool = new JedisPool(poolConfig, addr, port, 30000, password); // 30秒read timeout
		}
		
	}

	public static String getCacheKey(String... args) {
		
		if (args == null){
			throw new NullPointerException("缓存key不能为空！");
		}
		String[] array = args;
		StringBuffer sb = new StringBuffer();
		
		for (int i = 0; i < args.length; i++){
			if (i != 0){
				sb.append("-");
			}
			sb.append(array[i]);
		}
		return sb.toString();
	}
	
	public static void set(String key, String value){
		Jedis jedis = RedisUtils.getJedis();
		try{
			jedis.set(key, value);
		} finally {
			jedis.close();
		}
	}
	
	public static String get(String key){
		if(StringUtils.isBlank(key)){
			return null;
		}
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.get(key);
		} finally {
			jedis.close();
		}
	}
	
	public static long expire(String key, int seconds){
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.expire(key, seconds);
		} finally {
			jedis.close();
		}
	}
	
	/**
	 * 设置key值和过期时间，当存在key值时，重置value和过期时间
	 * @param key
	 * @param seconds
	 * @param value
	 * @return
	 */
	public static String setex(String key, int seconds, String value){
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.setex(key, seconds, value);
		} finally {
			jedis.close();
		}
	}
	
	public static Long del(String key){
		Jedis jedis = RedisUtils.getJedis();
		try{
			Long effect = jedis.del(key);
			return effect;
		} finally {
			jedis.close();
		}
	}
	
	public static Long lpush (String key,String value){
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.lpush(key, value);
		} finally {
			jedis.close();
		}
	}
	
	public static Long lrem (String key,String value){
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.lrem(key, 1, value);
		} finally {
			jedis.close();
		}
	}
	
	public static List<String> lrange (String key){
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.lrange(key, 0, -1);
		} finally {
			jedis.close();
		}
	}
	
	public static Long hSet (String key,String field,String value){
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.hset(key, field, value);
		} finally {
			jedis.close();
		}
	}
	
	public static String hGet (String key,String field){
		Jedis jedis = RedisUtils.getJedis();
		try{
			return jedis.hget(key, field);
		} finally {
			jedis.close();
		}
	}
	
	 /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {
    	Jedis jedis = RedisUtils.getJedis();
    	try{
	        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
	        if (LOCK_SUCCESS.equals(result)) {
	            return true;
	        }
	        return false;
		} finally {
			jedis.close();
		}
    }
    
    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(String lockKey, String requestId) {
    	Jedis jedis = RedisUtils.getJedis();
    	try{
    		String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
	        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
	        if (RELEASE_SUCCESS.equals(result)) {
	            return true;
	        }
	        return false;
		} finally {
			jedis.close();
		}
    }

}
